// Import React dependencies.
import React, { useState, ReactNode } from 'react';
import { Layout } from 'antd';
// Import the Slate editor factory.
import { createEditor, Transforms, Element, Editor, BaseEditor, Descendant } from 'slate';

// Import the Slate components and React plugin.
import { Slate, Editable, withReact, ReactEditor } from 'slate-react';

type CustomElement = { type: 'paragraph'; children: CustomText[] };
type CustomText = { text: string; type?: string };

declare module 'slate' {
    interface CustomTypes {
        Editor: BaseEditor & ReactEditor;
        Element: CustomElement;
        Text: CustomText;
    }
}
const initialValue: Descendant[] = [
    {
        type: 'paragraph',
        children: [{ text: 'A line of text in a paragraph.' }],
    },
];

interface IProps {
    children: ReactNode;
    attributes: {
        [key: string]: any;
    };
    [key: string]: any;
}

// Define a React component renderer for our code blocks.
function CodeElement(props: IProps) {
    const { attributes, children } = props;
    return (
        <pre {...attributes}>
            <code>{children}</code>
        </pre>
    );
}
function DefaultElement(props: IProps) {
    const { attributes, children } = props;
    return <p {...attributes}>{children}</p>;
}

interface RenderElementProps {
    element: {
        type: string;
        [key: string]: any;
    };
    children: ReactNode;
    attributes: {
        [key: string]: any;
    };
    [key: string]: any;
}
const renderElement = (props: RenderElementProps) => {
    switch (props.element.type) {
        case 'code':
            return <CodeElement {...props} />;
        default:
            return <DefaultElement {...props} />;
    }
};

export default function App() {
    const [editor] = useState(() => withReact(createEditor()));

    return (
        <Layout>
            <Slate editor={editor} initialValue={initialValue}>
                <Editable
                    renderElement={renderElement}
                    onKeyDown={(event) => {
                        if (event.key === '&') {
                            event.preventDefault();
                            editor.insertText('and');
                        } else if (event.key === '`' && event.ctrlKey) {
                            event.preventDefault();
                            // Determine whether any of the currently selected blocks are code blocks.
                            const [match] = Editor.nodes(editor, {
                                match: (n: any) => n.type === 'code',
                            });
                            // Toggle the block type depending on whether there's already a match.
                            Transforms.setNodes(
                                editor,
                                { type: match ? 'paragraph' : 'code' },
                                { match: (n) => Element.isElement(n) && Editor.isBlock(editor, n) },
                            );
                        }
                    }}
                />
            </Slate>
        </Layout>
    );
}
